package client;

import java.io.IOException;
import java.io.InputStream;

import javax.net.ssl.SSLSocket;

import client.Monitor;

public class ClientBackendThread extends Thread {

	private SSLSocket socket;
	private InputStream inputstream;
	private Monitor monitor;
	private final int sizeOfInt = Integer.SIZE / Byte.SIZE; // Size of int in bytes
	private boolean isBound;
	
	/**
	 * Starts the main handler for inbound server-client communication.
	 * @param monitor The monitor for the different threads in the client back-end.
	 * @param socket The socket for the server.
	 */
	public ClientBackendThread(Monitor monitor, SSLSocket socket) {
		try {
			this.socket = socket;
			this.inputstream = socket.getInputStream();
			this.monitor = monitor;
			isBound = true;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Closes the connection to the server
	 * @return if it succeeded
	 */
	public synchronized boolean unbindSocket() {
		if (socket != null) {
			try {
				socket.close();
				isBound = false;
				return true;
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}
		}
		return true; // if socket == null no need to close it
	}

	/**
	 * The main method. Responsible for receiving documents from the server over the network.
	 */
	public void run() {
		while (true) {
			try {
				readStream();
			} catch (IOException e) {
				System.out.println("Disconnecting...");
				System.exit(-1);
			}
		}
	}

	/**
	 * Interprets data from data stream
	 * @throws IOException if the data stream throws an error
	 */
	private void readStream() throws IOException {
		byte headerData[] = new byte[2*sizeOfInt];
		if (!isBound) {
			throw new IOException();
		}
		
		int size = 0;
		int header = 0;
		int command = 0;
		while (size == 0) {
			header = 0;
			while(header != 2*sizeOfInt){
				header += inputstream.read(headerData, header, 2*sizeOfInt - header);
			}
			command = byteArrayToInt(headerData, 0);
			size = byteArrayToInt(headerData, sizeOfInt);
		}
		byte data[] = new byte[size];
				
		int bytesRead = 0;
		while(bytesRead != size){
			bytesRead += inputstream.read(data, bytesRead, size - bytesRead);			
		}
		
		String dataString = new String(data);
		
		switch (command) {
		case 4: 
		case 5:
		case 6:
		case 7:
			monitor.setDisplayMessage(command, "done!");
			break;
		case 1:
		case 2:
		case 3:
		default:
			monitor.setDisplayMessage(command,dataString);
			break;
		}
	}
	
	/**
	 * Helper method to extract header information
	 * @param b byte[] to extract from
	 * @param offset where in b the header info is
	 * @return the header info as an int
	 */
	private final int byteArrayToInt(byte[] b, int offset) {
		return (b[0 + offset] << 24) + ((b[1 + offset] & 0xFF) << 16)
				+ ((b[2 + offset] & 0xFF) << 8) + (b[3 + offset] & 0xFF);
	}
}